package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"sort"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/logger"
	"gitee.com/sansaniot/ssiot-core/sdk/service"
	"github.com/tidwall/sjson"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	cDto "ssdevice/common/dto"
	"ssdevice/common/enums"
	"ssdevice/common/middleware/mqtt"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/models/query"
)

type Device struct {
	sysDevModel    *models.SysDev
	devSchemaModel *models.SysDevSchema
	devConfigModel *models.SysDevConfig
	devSensorModel *models.SysDevSensor
	devSystemModel *models.SysDevSystem
	productModel   *models.SysDevProduct
	service.Service
}

func (d *Device) SetDevModel(m *models.SysDev) *Device {
	d.sysDevModel = m
	return d
}

func (d *Device) SetSchemaModel(m *models.SysDevSchema) *Device {
	d.devSchemaModel = m
	return d
}

func (d *Device) SetConfigModel(m *models.SysDevConfig) *Device {
	d.devConfigModel = m
	return d
}

func (d *Device) SetSensorModel(m *models.SysDevSensor) *Device {
	d.devSensorModel = m
	return d
}

func (d *Device) SetSystemModel(m *models.SysDevSystem) *Device {
	d.devSystemModel = m
	return d
}

func (d *Device) SetProductModel(m *models.SysDevProduct) *Device {
	d.productModel = m
	return d
}

func (d *Device) SetAllModel() {
	d.sysDevModel = &models.SysDev{}
	d.devSchemaModel = &models.SysDevSchema{}
	d.devConfigModel = &models.SysDevConfig{}
	d.devSensorModel = &models.SysDevSensor{}
	d.devSystemModel = &models.SysDevSystem{}
	d.productModel = &models.SysDevProduct{}
	d.sysDevModel.Orm = d.Orm
	d.devSchemaModel.Orm = d.Orm
	d.devConfigModel.Orm = d.Orm
	d.devSensorModel.Orm = d.Orm
	d.devSystemModel.Orm = d.Orm
	d.productModel.Orm = d.Orm
}

func generateSchema(db *gorm.DB, dev *models.SysDev) *models.SysDevSchema {
	now := cDto.LocalTime(time.Now())
	var schema string
	if dev.Type == enums.DevTypeOfDevice {
		schema = constant.DevSchemaTemplate
		if len(dev.GatewaySn) > 0 {
			// 按照gateway生成初始
			schemaModel := &models.SysDevSchema{}
			schemaModel.Orm = db
			_, fromGatewaySchema := schemaModel.FindDevSchema(&query.SysDevSchemaQuery{Sn: dev.GatewaySn, Path: "properties.config.properties.subdevice.properties"})
			if len(fromGatewaySchema.Id) > 0 && len(fromGatewaySchema.Schema) > 0 {
				tmpSchemaJson := utils.BytesToMap(fromGatewaySchema.Schema)
				devSchemaTemplateObj := utils.BytesToMap([]byte(schema))
				devSchemaTemplateObj["properties"].(map[string]interface{})["config"].(map[string]interface{})["properties"] = tmpSchemaJson
				schema = string(utils.MapToBytes(devSchemaTemplateObj))
			}
		}
	} else {
		schema = constant.GatewaySchemaTemplate
	}
	return &models.SysDevSchema{
		Id:         utils.SimpleUUID(),
		DevSn:      dev.Sn,
		Schema:     []byte(schema),
		CreateTime: &now,
		UpdateTime: &now,
	}
}

func generateProfile(db *gorm.DB, dev *models.SysDev, formProductConfig models.SysDevConfig, req *command.DeviceInsertReq) (*models.SysDevConfig, *models.SysDevSensor, *models.SysDevSystem) {
	sn := dev.Sn
	devType := dev.Type
	var config string
	if devType == enums.DevTypeOfDevice {
		config = constant.DevConfigTemplate
		// 同时有产品、网关时, 取产品的
		if len(formProductConfig.Data) > 0 {
			// 按产品config
			config = string(formProductConfig.Data)
		} else if len(dev.GatewaySn) > 0 {
			// 按照gateway生成初始
			configModel := &models.SysDevConfig{}
			configModel.Orm = db
			_ = configModel.FindDevConfig(&query.SysDevConfigQuery{Sn: dev.GatewaySn})
			fromGatewayConfig := utils.GetFieldFromJson([]string{"config", "subdevice"}, utils.BytesToMap(configModel.Data))
			if fromGatewayConfig != nil && len(fromGatewayConfig.(map[string]interface{})) > 0 {
				devConfigTemplateObj := utils.BytesToMap([]byte(config))
				fromGatewayConfigMap := fromGatewayConfig.(map[string]interface{})
				// 跟随网关profile但置空sensor
				fromGatewayConfigMap["sensor"] = map[string]interface{}{}
				devConfigTemplateObj["config"] = fromGatewayConfigMap
				config = string(utils.MapToBytes(devConfigTemplateObj))
			}
		}
	} else {
		config = constant.GatewayConfigTemplate
	}
	if len(req.ProfileCustom) > 0 {
		for k, v := range req.ProfileCustom {
			config, _ = sjson.Set(config, k, v)
		}
	}
	now := cDto.LocalTime(time.Now())
	return &models.SysDevConfig{
			Id:         utils.SimpleUUID(),
			DevSn:      sn,
			Data:       []byte(config),
			CreateTime: &now,
			UpdateTime: &now,
		}, &models.SysDevSensor{
			Id:         utils.SimpleUUID(),
			DevSn:      sn,
			Data:       []byte(utils.If(devType == enums.DevTypeOfDevice, constant.DevSensorTemplate, constant.GatewaySensorTemplate).(string)),
			CreateTime: &now,
			UpdateTime: &now,
		}, &models.SysDevSystem{
			Id:         utils.SimpleUUID(),
			DevSn:      sn,
			Data:       []byte(utils.If(devType == enums.DevTypeOfDevice, constant.DevSystemTemplate, constant.GatewaySystemTemplate).(string)),
			CreateTime: &now,
			UpdateTime: &now,
		}
}

// 添加设备
func (d *Device) AddDevice(req *command.DeviceInsertReq) (err error, dev models.SysDev) {
	var fromProductSchema models.SysDevSchema
	var formProductConfig models.SysDevConfig
	if fromProductSchema, formProductConfig, err = req.Generate(d.Orm, &dev); err != nil {
		return
	}
	if err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.sysDevModel.Orm = tx
		d.devSchemaModel.Orm = tx
		d.devConfigModel.Orm = tx
		d.devSensorModel.Orm = tx
		d.devSystemModel.Orm = tx
		// 添加设备基本信息
		if err = d.sysDevModel.AddDevice(&dev); err != nil {
			return err
		}
		// 设备schema
		var addSchema *models.SysDevSchema
		if len(fromProductSchema.Id) > 0 {
			addSchema = &fromProductSchema
		} else {
			addSchema = generateSchema(d.Orm, &dev)
		}
		if err = d.devSchemaModel.Add(addSchema); err != nil {
			return err
		}
		devConfig, devSensor, devSystem := generateProfile(d.Orm, &dev, formProductConfig, req)
		// 设备profile.config
		if err = d.devConfigModel.Add(devConfig); err != nil {
			return err
		}
		// 设备profile.sensor
		if err = d.devSensorModel.Add(devSensor); err != nil {
			return err
		}
		// 设备profile.system
		if err = d.devSystemModel.Add(devSystem); err != nil {
			return err
		}
		// 软网关添加时，调用服务进程(放在后面-保证事务回滚)
		if dev.Type == enums.DevTypeOfSoftGateway && !req.FromLoginInit {
			if err = ctrlSoftGatewayServe(&dev, enums.Add); err != nil {
				return err
			}
		}
		// 缓存设备分组
		_ = env.Cache.HashSet(constant.DeviceDeptCache, map[string]interface{}{dev.Sn: dev.DeptId})
		// 缓存设备信息
		_ = env.Cache.HashSet(constant.DeviceEasyCache, map[string]interface{}{dev.Sn: dev.Type})
		// 广播消息
		mqtt.MqttClient.Publish(constant.DeviceAddMsgTopic, utils.MapToBytes(map[string]interface{}{"sn": dev.Sn}))
		return nil
	}); err != nil {
		return
	}
	return
}

// 删除设备
func (d *Device) DeleteDevice(req *command.DeviceDeleteReq) (err error) {
	delIdSns := strings.Split(strings.ReplaceAll(req.IdSn, " ", ""), ",")
	if req.DelType == enums.DevTypeOfSoftGateway && len(delIdSns) > 1 {
		err = errors.New("软网关不支持批量删除")
		return
	}
	var delDevList []models.SysDev
	if err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.sysDevModel.Orm = tx
		d.devSchemaModel.Orm = tx
		d.devConfigModel.Orm = tx
		d.devSensorModel.Orm = tx
		d.devSystemModel.Orm = tx
		// 批量操作
		snList := make([]string, 0)
		if delDevList, err = getBatchDelDev(d.sysDevModel, req, &snList); err != nil {
			return err
		}
		if len(snList) == 0 {
			return nil
		}
		// 设备基本信息
		if err = d.sysDevModel.Delete(&models.SysDev{}, cDto.MakeCondition(query.SysDevQuery{SnIn: snList})); err != nil {
			return err
		}
		// 设备schema
		if err = d.devSchemaModel.Delete(&models.SysDevSchema{}, cDto.MakeCondition(query.SysDevSchemaQuery{SnIn: snList})); err != nil {
			return err
		}
		// 设备profile.config
		if err = d.devConfigModel.Delete(&models.SysDevConfig{}, cDto.MakeCondition(query.SysDevConfigQuery{SnIn: snList})); err != nil {
			return err
		}
		// 设备profile.sensor
		if err = d.devSensorModel.Delete(&models.SysDevSensor{}, cDto.MakeCondition(query.SysDevSensorQuery{SnIn: snList})); err != nil {
			return err
		}
		// 设备profile.system
		if err = d.devSystemModel.Delete(&models.SysDevSystem{}, cDto.MakeCondition(query.SysDevSystemQuery{SnIn: snList})); err != nil {
			return err
		}
		// 删除软网关，调用服务进程(放在后面-保证事务回滚)
		if req.DelType == enums.DevTypeOfSoftGateway {
			if err = ctrlSoftGatewayServe(&models.SysDev{Sn: snList[0]}, enums.Remove); err != nil {
				return err
			}
		}
		// 删分组/设备缓存
		for _, s := range snList {
			_ = env.Cache.HashDel(constant.DeviceDeptCache, s)
			_ = env.Cache.HashDel(constant.DeviceEasyCache, s)
		}
		// 广播消息
		mqtt.MqttClient.Publish(constant.DeviceDeleteMsgTopic, utils.MapToBytes(map[string]interface{}{"sn": strings.Join(snList, ",")}))
		return nil
	}); err != nil {
		return
	}
	// 下发空配置
	for _, v := range delDevList {
		setEmptyConfig(v)
	}
	return
}

func getBatchDelDev(d *models.SysDev, req *command.DeviceDeleteReq, snList *[]string) (devList []models.SysDev, err error) {
	// 查询设备
	devList = make([]models.SysDev, 0)
	delIdSns := strings.Split(strings.ReplaceAll(req.IdSn, " ", ""), ",")
	if err = d.FindList(&devList, cDto.MakeCondition(query.SysDevQuery{IdSnIn: delIdSns})); err != nil {
		return
	}
	// sn-gate关系
	for _, v := range devList {
		*snList = append(*snList, v.Sn)
	}
	//判断网关能否删
	if req.DelType != enums.DevTypeOfDevice {
		var count int64
		if err = d.FindCount(d, &count, cDto.MakeCondition(query.SysDevQuery{GatewaySnIn: *snList})); err != nil {
			return
		}
		if count > 0 {
			err = errors.New("网关存在下位机配置, 无法删除")
		}
	}
	return
}

func setEmptyConfig(sysDev models.SysDev) {
	var gateSn, to string
	if sysDev.Type == enums.DevTypeOfDevice {
		gateSn = utils.If(len(sysDev.GatewaySn) > 0, sysDev.GatewaySn, sysDev.Sn).(string)
		to = sysDev.Sn
	} else {
		gateSn = sysDev.Sn
		to = ""
	}
	// 下发终端
	topic := fmt.Sprintf("/iot/%s/%s/config/set", gateSn, constant.TopicPlaceholder)
	content := make(map[string]interface{})
	sid := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(100000)
	content["sid"] = sid
	content["from"] = constant.TopicPlaceholder
	content["to"] = to
	content["data"] = nil
	contentBytes, _ := json.Marshal(content)
	mqtt.MqttClient.Publish(topic, contentBytes)
}

// 批量分组
func (d *Device) ChangeGroup(req *command.BatchGroupReq) error {
	idList := strings.Split(strings.ReplaceAll(req.IdSn, " ", ""), ",")
	devices := make([]models.SysDev, 0)
	condition := cDto.MakeCondition(query.SysDevQuery{IdSnIn: idList})
	if err := d.sysDevModel.FindList(&devices, condition); err != nil {
		return err
	}
	if len(devices) == 0 {
		return errors.New("设备不存在")
	}
	hmsetMap := make(map[string]interface{})
	for _, v := range devices {
		hmsetMap[v.Sn] = req.DeptId
	}
	if err := d.Orm.Transaction(func(tx *gorm.DB) error {
		d.sysDevModel.Orm = tx
		if err := d.sysDevModel.ModMap(d.sysDevModel, map[string]interface{}{"dept_id": req.DeptId}, condition); err != nil {
			return err
		}
		if err := env.Cache.HashSet(constant.DeviceDeptCache, hmsetMap); err != nil {
			return errors.New("缓存出现异常" + err.Error())
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// 设备配置下发
func (d *Device) SetDeviceConfig(req *command.DevicePropsSetReq) (err error) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	// 获取设备配置
	if err = d.devConfigModel.FindDevConfig(&query.SysDevConfigQuery{Sn: sysDev.Sn}); err != nil {
		return
	}
	configData := utils.BytesToMap(d.devConfigModel.Data)["config"].(map[string]interface{})
	var gateSn, to string
	if sysDev.Type == enums.DevTypeOfDevice {
		gateSn = utils.If(len(sysDev.GatewaySn) > 0, sysDev.GatewaySn, sysDev.Sn).(string)
		to = sysDev.Sn
	} else {
		gateSn = sysDev.Sn
		to = ""
		//// 组装子设备config
		//var subdeviceJson map[string]interface{}
		//if subdeviceJson, err = d.devConfigModel.GetSubDeviceConfig(gateSn); err != nil {
		//	return
		//}
		//configData["subdevice"] = subdeviceJson
	}
	// 下发终端
	topic := fmt.Sprintf("/iot/%s/%s/config/set", gateSn, constant.TopicPlaceholder)
	content := make(map[string]interface{})
	sid := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(100000)
	content["sid"] = sid
	content["from"] = constant.TopicPlaceholder
	content["to"] = to
	content["data"] = configData
	contentBytes, _ := json.Marshal(content)
	// 同步处理, 订阅响应
	subT := fmt.Sprintf("/iot/%s/%s/config/set/ack", constant.TopicPlaceholder, sysDev.Sn)
	// 同步下发
	if err = mqtt.MqttClient.SyncSend(topic, contentBytes, sid, subT, func(msgInfo map[string]interface{}, e *error) {}); err != nil {
		mqtt.MqttClient.UnSubscribe(subT)
	}
	return
}

// 查询设备配置
func (d *Device) GetDeviceConfig(req *command.DevicePropsGetReq) (err error, result interface{}) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	var gateSn, to string
	if sysDev.Type == enums.DevTypeOfDevice {
		gateSn = utils.If(len(sysDev.GatewaySn) > 0, sysDev.GatewaySn, sysDev.Sn).(string)
		to = sysDev.Sn
	} else {
		gateSn = sysDev.Sn
		to = ""
	}
	// 下发终端
	topic := fmt.Sprintf("/iot/%s/%s/config/get", gateSn, constant.TopicPlaceholder)
	content := make(map[string]interface{})
	sid := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(100000)
	content["sid"] = sid
	content["from"] = constant.TopicPlaceholder
	content["to"] = to
	content["data"] = map[string]interface{}{
		"path": req.Path,
	}
	contentBytes, _ := json.Marshal(content)
	// 同步处理, 订阅响应
	subT := fmt.Sprintf("/iot/%s/%s/config/get/ack", constant.TopicPlaceholder, sysDev.Sn)
	// 同步下发
	if err = mqtt.MqttClient.SyncSend(topic, contentBytes, sid, subT, func(msgInfo map[string]interface{}, e *error) {
		// 响应回调处理
		result = msgInfo["data"]
		if result == nil {
			return
		}
		dataStr := string(utils.MapToBytes(result.(map[string]interface{})))
		path := "{config}"
		if len(req.Path) > 0 {
			path = "{config"
			for _, v := range strings.Split(req.Path, ".") {
				path += "," + v
			}
			path += "}"
		}
		sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', jsonb_update(data #> '" + path + "', '" + dataStr + "' :: jsonb ) ) where dev_sn = '%s'"
		// 防止字符串中存在?占位符
		sql = fmt.Sprintf(sql, sysDev.Sn)
		if err := d.Orm.Raw(sql).Scan(&models.SysDevConfig{}).Error; err != nil {
			logger.Error(err)
		}
		go func() {
			devSchema := &models.SysDevSchema{}
			devSchema.Orm = d.Orm
			devSchema.InferConfigSchemaMerge(sysDev.Sn, result.(map[string]interface{}), req.Path)
		}()
	}); err != nil {
		mqtt.MqttClient.UnSubscribe(subT)
	}
	return
}

// 设备变量下发
func (d *Device) SetDeviceSensor(req *command.DeviceSensorSetReq) (err error) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	var gateSn, to string
	if sysDev.Type == enums.DevTypeOfDevice {
		gateSn = utils.If(len(sysDev.GatewaySn) > 0, sysDev.GatewaySn, sysDev.Sn).(string)
		to = sysDev.Sn
	} else {
		gateSn = sysDev.Sn
		to = ""
	}
	// 下发终端
	topic := fmt.Sprintf("/iot/%s/%s/sensor/set", gateSn, constant.TopicPlaceholder)
	content := make(map[string]interface{})
	sid := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(100000)
	content["sid"] = sid
	content["from"] = constant.TopicPlaceholder
	content["to"] = to
	content["data"] = req.Data
	contentBytes, _ := json.Marshal(content)
	// 同步处理, 订阅响应
	subT := fmt.Sprintf("/iot/%s/%s/sensor/set/ack", constant.TopicPlaceholder, sysDev.Sn)
	// 同步下发
	if err = mqtt.MqttClient.SyncSend(topic, contentBytes, sid, subT, func(msgInfo map[string]interface{}, e *error) {
		if e != nil {
			return
		}
		// 下发成功后, 更新实时数据 - profile变量值
		if err = d.devSensorModel.UpdateDevSensor(sysDev.Sn, req.Data); err != nil {
			return
		}
	}); err != nil {
		mqtt.MqttClient.UnSubscribe(subT)
	}
	return
}

// 设备下发控制
func (d *Device) SendDeviceFunc(req *command.DeviceFuncSetReq) (result interface{}, err error) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	var gateSn, to string
	if sysDev.Type == enums.DevTypeOfDevice {
		gateSn = utils.If(len(sysDev.GatewaySn) > 0, sysDev.GatewaySn, sysDev.Sn).(string)
		to = sysDev.Sn
	} else {
		gateSn = sysDev.Sn
		to = ""
	}
	// 下发终端
	topic := fmt.Sprintf("/iot/%s/%s/func/%s", gateSn, constant.TopicPlaceholder, req.FuncName)
	content := make(map[string]interface{})
	sid := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(100000)
	content["sid"] = sid
	content["from"] = constant.TopicPlaceholder
	content["to"] = to
	content["data"] = req.Data
	contentBytes, _ := json.Marshal(content)
	// 同步处理, 订阅响应
	subT := fmt.Sprintf("/iot/%s/%s/func/%s/ack", constant.TopicPlaceholder, sysDev.Sn, req.FuncName)
	// 同步下发
	if err = mqtt.MqttClient.SyncSend(topic, contentBytes, sid, subT, func(msgInfo map[string]interface{}, e *error) {
		result = msgInfo["data"]
	}); err != nil {
		mqtt.MqttClient.UnSubscribe(subT)
	}
	return
}

// 查询设备profile
func (d *Device) FindDevProfile(req *query.SysDevProfileQuery) (err error, result map[string]interface{}) {
	result = map[string]interface{}{}
	profile := map[string]interface{}{}
	props := map[string]interface{}{}
	profile["props"] = props
	result["profile"] = profile
	if len(req.IdSn) > 0 {
		if err = d.sysDevModel.FindOne(d.sysDevModel, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
			return
		}
		result["devSn"] = d.sysDevModel.Sn
		result["productModel"] = d.sysDevModel.ProductModel
		result["createTime"] = d.sysDevModel.CreateTime
		result["updateTime"] = d.sysDevModel.UpdateTime
		// 查询config
		if err = d.devConfigModel.FindOne(d.devConfigModel, cDto.MakeCondition(query.SysDevConfigQuery{Sn: d.sysDevModel.Sn})); err != nil {
			return
		}
		utils.DeepMerge(utils.DataToMap(d.devConfigModel.Data), profile)
		// 基本信息
		props["basic"] = utils.DataToMap(*d.sysDevModel)
		// 查询sensor
		if err = d.devSensorModel.FindOne(d.devSensorModel, cDto.MakeCondition(query.SysDevSensorQuery{Sn: d.sysDevModel.Sn})); err != nil {
			return
		}
		utils.DeepMerge(utils.DataToMap(d.devSensorModel.Data), profile)
		// 查询system
		if err = d.devSystemModel.FindOne(d.devSystemModel, cDto.MakeCondition(query.SysDevSystemQuery{Sn: d.sysDevModel.Sn})); err != nil {
			return
		}
		utils.DeepMerge(utils.DataToMap(d.devSystemModel.Data), props)
	} else if len(req.ProductId) > 0 {
		if err = d.productModel.FindOne(d.productModel, cDto.MakeCondition(query.SysProductQuery{Id: req.ProductId})); err != nil {
			return
		}
		result["devSn"] = ""
		result["productModel"] = d.productModel.ProductModel
		result["devProductId"] = d.productModel.Id
		result["createTime"] = d.productModel.CreateTime
		result["updateTime"] = d.productModel.UpdateTime
		// 查询config
		if err = d.devConfigModel.FindOne(d.devConfigModel, cDto.MakeCondition(query.SysDevConfigQuery{ProductId: d.productModel.Id})); err != nil {
			return
		}
		utils.DeepMerge(utils.DataToMap(d.devConfigModel.Data), profile)
		// 基本信息
		props["basic"] = utils.DataToMap(*d.productModel)
		// system
		props["system"] = map[string]interface{}{}
		// sensor
		profile["sensor"] = map[string]interface{}{}
	} else {
		err = errors.New("查询异常")
		return
	}
	// path处理
	if len(req.Path) > 0 {
		paths := strings.Split(req.Path, ".")
		result["profile"] = utils.GetFieldFromJson(paths, profile)
	}
	return
}

// 查询设备历史数据
func (d *Device) GetDeviceHistoryData(req *query.DevDataQuery) (err error, result []map[string]interface{}) {
	if err = d.sysDevModel.FindOne(d.sysDevModel, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	keySplit := strings.Split(req.Key, ".")
	rootKey := keySplit[0]
	tableName := "sys_history_" + req.KeyType
	exist := d.Orm.Migrator().HasTable(tableName)
	if !exist {
		err = errors.New("查询历史数据,表不存在")
		return
	}
	whereSql := "dev_sn = ? and key = ?"
	cond := make([]interface{}, 0)
	cond = append(cond, d.sysDevModel.Sn)
	cond = append(cond, rootKey)
	if len(req.StartTime) > 0 {
		whereSql += " and update_time>=?"
		cond = append(cond, req.StartTime)
	}
	if len(req.EndTime) > 0 {
		whereSql += " and update_time<=?"
		cond = append(cond, req.EndTime)
	}
	// 默认增序
	timeOrder := utils.If(strings.ToUpper(req.TimeOrder) == "DESC", "DESC", "ASC").(string)
	// 不传时间，默认查询最新1000条记录
	defaultLimit := len(req.StartTime) == 0 && len(req.EndTime) == 0
	if defaultLimit {
		whereSql += " ORDER BY update_time DESC limit 1000 "
	} else {
		whereSql += " ORDER BY update_time " + timeOrder
	}
	if err = d.Orm.Table(tableName).Where(whereSql, cond...).Scan(&result).Error; err != nil {
		return
	}
	for _, v := range result {
		v["devSn"] = v["dev_sn"].(string)
		v["updateTime"] = utils.FormatTimeToStr(v["update_time"].(time.Time))
		if v["value"] != nil {
			valueStr := v["value"].(string)
			if strings.HasPrefix(valueStr, "{") && strings.HasSuffix(valueStr, "}") {
				valueObj := utils.JsonStrToMap(valueStr)
				v["value"] = valueObj
				if len(keySplit) > 1 {
					v["value"] = utils.GetFieldFromJson(keySplit[1:], valueObj)
				}
			} else if len(keySplit) > 1 {
				v["value"] = nil
			}
		}
		delete(v, "dev_sn")
		delete(v, "update_time")
	}
	// 矫正顺序
	if defaultLimit {
		sort.Slice(result, func(i, j int) bool {
			if timeOrder == "ASC" {
				return result[i]["updateTime"].(string) < result[j]["updateTime"].(string)
			} else {
				return result[i]["updateTime"].(string) >= result[j]["updateTime"].(string)
			}
		})
	}
	return
}

// 查询多设备历史数据
func (d *Device) FindDeviceHistoryData(req *query.MultiDevDataQuery) (err error, result []map[string]interface{}) {
	// 不允许都不传
	if len(req.IdSn) == 0 && len(req.ProductModel) == 0 {
		return
	}
	// 根据条件定位sns
	q := query.SysDevQuery{}
	if len(req.IdSn) > 0 {
		q.IdSnIn = strings.Split(strings.ReplaceAll(req.IdSn, " ", ""), ",")
	}
	if len(req.ProductModel) > 0 {
		q.ProductModel = req.ProductModel
	}
	var devList []models.SysDev
	var devSns []string
	if err = d.Orm.Model(&devList).Scopes(cDto.MakeCondition(q)).Distinct().Pluck("sn", &devSns).Error; err != nil {
		return
	}
	// 确定sensor/system表
	keySplit := strings.Split(req.Key, ".")
	rootKey := keySplit[0]
	tableName := "sys_history_" + req.KeyType
	exist := d.Orm.Migrator().HasTable(tableName)
	if !exist {
		err = errors.New("查询历史数据,表不存在")
		return
	}
	whereSql := "dev_sn in ? and key = ?"
	cond := make([]interface{}, 0)
	cond = append(cond, devSns)
	cond = append(cond, rootKey)
	// 值不为空
	if req.HasValue {
		whereSql += " and value is not null and value != '' "
	}
	if len(req.StartTime) > 0 {
		whereSql += " and update_time>=?"
		cond = append(cond, req.StartTime)
	}
	if len(req.EndTime) > 0 {
		whereSql += " and update_time<=?"
		cond = append(cond, req.EndTime)
	}
	// 默认增序
	timeOrder := utils.If(strings.ToUpper(req.TimeOrder) == "DESC", "DESC", "ASC").(string)
	// 不传时间，默认查询最新1000条记录
	defaultLimit := len(req.StartTime) == 0 && len(req.EndTime) == 0
	if defaultLimit {
		whereSql += " ORDER BY update_time DESC limit 1000 "
	} else {
		whereSql += " ORDER BY update_time " + timeOrder
	}
	if err = d.Orm.Table(tableName).Where(whereSql, cond...).Scan(&result).Error; err != nil {
		return
	}
	for _, v := range result {
		v["devSn"] = v["dev_sn"].(string)
		v["updateTime"] = utils.FormatTimeToStr(v["update_time"].(time.Time))
		if v["value"] != nil {
			valueStr := v["value"].(string)
			if strings.HasPrefix(valueStr, "{") && strings.HasSuffix(valueStr, "}") {
				valueObj := utils.JsonStrToMap(valueStr)
				v["value"] = valueObj
				if len(keySplit) > 1 {
					v["value"] = utils.GetFieldFromJson(keySplit[1:], valueObj)
				}
			} else if len(keySplit) > 1 {
				v["value"] = nil
			}
		}
		delete(v, "dev_sn")
		delete(v, "update_time")
	}
	// 矫正顺序
	if defaultLimit {
		sort.Slice(result, func(i, j int) bool {
			if timeOrder == "ASC" {
				return result[i]["updateTime"].(string) < result[j]["updateTime"].(string)
			} else {
				return result[i]["updateTime"].(string) >= result[j]["updateTime"].(string)
			}
		})
	}
	return
}

// 设备保存为产品
func (d *Device) DeviceSaveProduct(req *command.DeviceSaveProductReq) (err error) {
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil {
		return
	}
	productInsert := command.ProductInsertReq{}
	if err = req.GenerateProduct(&sysDev, &productInsert); err != nil {
		return
	}
	// 查询设备schema
	if err = d.devSchemaModel.FindOne(d.devSchemaModel, cDto.MakeCondition(query.SysDevSchemaQuery{Sn: sysDev.Sn})); err != nil {
		return
	}
	// 查询设备config
	if err = d.devConfigModel.FindOne(d.devConfigModel, cDto.MakeCondition(query.SysDevConfigQuery{Sn: sysDev.Sn})); err != nil {
		return
	}
	productInsert.DevSchema = d.devSchemaModel
	productInsert.DevConfig = d.devConfigModel
	// 添加产品
	sp := &Product{}
	sp.Orm = d.Orm
	sp.SetAllModel()
	err, _ = sp.AddProduct(&productInsert)
	return
}

// 配置整体操作schema
func (d *Device) UpsertEntireSchemaConfig(req *command.DeviceConfigReq) (err error) {
	sqlReplace := "dev_sn"
	sqlReplaceId := ""
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}
	sqlReplaceId = sysDev.Sn
	if len(sysDev.Id) == 0 {
		sysProduct := models.SysDevProduct{}
		if err = d.productModel.FindOne(&sysProduct, cDto.MakeCondition(query.SysProductQuery{Id: req.IdSn})); err != nil {
			return
		}
		sqlReplace = "dev_product_id"
		sqlReplaceId = sysProduct.Id
	}
	// 更新网关配置 schema.properties.config
	toBytes := utils.MapToBytes(req.Data)
	paths := "{properties,config}"
	if len(req.NodePath) > 0 {
		paths = "{" + strings.ReplaceAll(req.NodePath, ".", ",") + "}"
	}
	dataStr := string(toBytes)
	//sql := "update sys_dev_schema set schema = jsonb_set(schema::jsonb, '" + paths + "', '" + dataStr + "' :: jsonb ) where dev_sn = '%s'"
	sql := "update sys_dev_schema set schema = jsonb_set(schema::jsonb, '" + paths + "', '" + dataStr + "' :: jsonb ) "
	where := " where %s = '%s' "
	// 防止字符串中存在?占位符
	sql += fmt.Sprintf(where, sqlReplace, sqlReplaceId)
	if err = d.Orm.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
		return err
	}
	return
}

// 配置整体操作
func (d *Device) UpsertEntireConfig(req *command.DeviceConfigReq) (err error) {
	sqlReplace := "dev_sn"
	sqlReplaceId := ""

	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}
	sqlReplaceId = sysDev.Sn
	if len(sysDev.Id) == 0 {
		sysProduct := models.SysDevProduct{}
		if err = d.productModel.FindOne(&sysProduct, cDto.MakeCondition(query.SysProductQuery{Id: req.IdSn})); err != nil {
			return
		}
		sqlReplace = "dev_product_id"
		sqlReplaceId = sysProduct.Id
	}
	// 整体替换网关的profile.config
	path := "{config}"
	if len(req.NodePath) > 0 {
		path = "{" + strings.ReplaceAll(req.NodePath, ".", ",") + "}"
	}
	dataStr := string(utils.MapToBytes(req.Data))
	//sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', '" + dataStr + "' :: jsonb ) where dev_sn = '%s'"
	sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', '" + dataStr + "' :: jsonb ) "
	where := " where %s = '%s' "
	// 防止字符串中存在?占位符
	sql += fmt.Sprintf(where, sqlReplace, sqlReplaceId)
	if err = d.Orm.Raw(sql).Scan(d.devConfigModel).Error; err != nil {
		return err
	}
	return
}

// 配置层次合并更新
func (d *Device) MergeModifyConfig(req *command.DeviceConfigReq) (err error) {
	sqlReplace := "dev_sn"
	sqlReplaceId := ""
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}
	sqlReplaceId = sysDev.Sn
	if len(sysDev.Id) == 0 {
		sysProduct := models.SysDevProduct{}
		if err = d.productModel.FindOne(&sysProduct, cDto.MakeCondition(query.SysProductQuery{Id: req.IdSn})); err != nil {
			return
		}
		sqlReplace = "dev_product_id"
		sqlReplaceId = sysProduct.Id
	}
	// 整体替换网关的profile.config
	path := "{config}"
	if len(req.NodePath) > 0 {
		path = "{" + strings.ReplaceAll(req.NodePath, ".", ",") + "}"
	}
	dataStr := string(utils.MapToBytes(req.Data))
	//sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', jsonb_update(data #> '" + path + "', '" + dataStr + "' :: jsonb ) ) where dev_sn = '%s'"
	sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', jsonb_update(data #> '" + path + "', '" + dataStr + "' :: jsonb ) ) "
	where := " where %s = '%s' "
	// 防止字符串中存在?占位符
	sql += fmt.Sprintf(where, sqlReplace, sqlReplaceId)
	if err = d.Orm.Raw(sql).Scan(d.devConfigModel).Error; err != nil {
		return err
	}
	return
}

// 层次合并操作schema
func (d *Device) MergeModifySchema(req *command.DeviceConfigReq) (err error) {
	sqlReplace := "dev_sn"
	sqlReplaceId := ""
	sysDev := models.SysDev{}
	if err = d.sysDevModel.FindOne(&sysDev, cDto.MakeCondition(query.SysDevQuery{IdSn: req.IdSn})); err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return
	}
	sqlReplaceId = sysDev.Sn
	if len(sysDev.Id) == 0 {
		sysProduct := models.SysDevProduct{}
		if err = d.productModel.FindOne(&sysProduct, cDto.MakeCondition(query.SysProductQuery{Id: req.IdSn})); err != nil {
			return
		}
		sqlReplace = "dev_product_id"
		sqlReplaceId = sysProduct.Id
	}

	// 更新网关配置 schema.properties.config
	toBytes := utils.MapToBytes(req.Data)
	paths := "{properties,config}"
	if len(req.NodePath) > 0 {
		paths = "{" + strings.ReplaceAll(req.NodePath, ".", ",") + "}"
	}
	dataStr := string(toBytes)
	//sql := "update sys_dev_schema set schema = jsonb_set(schema::jsonb, '" + paths + "', jsonb_update(schema #> '" + paths + "', '" + dataStr + "' :: jsonb ) ) where dev_sn = '%s'"
	sql := "update sys_dev_schema set schema = jsonb_set(schema::jsonb, '" + paths + "', jsonb_update(schema #> '" + paths + "', '" + dataStr + "' :: jsonb ) ) "
	where := " where %s = '%s' "
	// 防止字符串中存在?占位符
	sql += fmt.Sprintf(where, sqlReplace, sqlReplaceId)
	if err = d.Orm.Raw(sql).Scan(d.devSchemaModel).Error; err != nil {
		return err
	}
	return
}
